#!/usr/bin/python
# -*- coding: utf-8 -*-
# AUTHOR:   yemd
# FILENAME: py_common_log.py
# DESCRIBE: 日志打印封装库
# CREATED:  2014-01-15 14:29
# MODIFIED: 2014-02-11 13:41

import sys,os
import time
import string
import inspect
import logging
import logging.handlers
import py_config
#from dm_py_util import *


"""
日志打印级别
"""
LEVEL_TYPE_DICT = {10:"DEBUG",20:"INFO",30:"WARNING",40:"ERROR",50:"CRITICAL"}

"""
日志打印间隔：
   when(轮询单位) interval(间隔when个单位时间)  suffix(后缀名格式)
0: “M”: Minutes    1：每分钟					 min:   20140121-1801
1: “H”: Hours      1：每小时					 hour:  20140121-18
2: “D”: Days       1：每天						 day:   20140121
3: "D": Month      30：间隔30天					 month: 201401
4: "D": Year       365: 间隔365天				 year:  2014
"""
WHEN_DICT     = {0:"M", 1:"H", 2:"D", 3:"D", 4:"D"}
INTERNAL_DICT = {0:1,   1:1,   2:1,   3:30,  4:365}
SUFFIX_DICT   = {0:"%Y%m%d-%H%M",1:"%Y%m%d-%H",2:"%Y%m%d",3:"%Y%m",4:"%Y"}

"""
program： 程序日志：输出所有级别的日志(NOTSET除外)，用于调试和运行日志打印
error:    错误日志：只输出错误级别的日志（无严重级别错误,已专用于业务日志）
business：业务日志：只输出业务相关的日志，使用critical级别打印
"""
LOG_TYPE_DICT = {10:"program",40:"error",50:"business"} 

"""
控制台是否输出
"""
CONSOLE_TYPE_DICT = {0:"NO_CONSOLE",1:"PRINT_CONSOLE"}

#日志日期格式
DATEFORMAT='%Y/%m/%d %H:%M:%S'  



"""
common_logger不初始化，直接输出print内容，不打印到文件
"""
py_common_logger=None

def INIT_LOG(config):
	try:
		if not config:
			print 'config is None'
			return -1
		cfgparser = py_config.PYC_ConfigParser(config)
		Path = cfgparser.get_config("py_common_logger","log_path")
		Pre = cfgparser.get_config("py_common_logger","log_pre")
		Level = int(cfgparser.get_config("py_common_logger","log_level"))
		Interval = int(cfgparser.get_config("py_common_logger","log_interval"))
		Key = cfgparser.get_config("py_common_logger","log_key")
		Console = int(cfgparser.get_config("py_common_logger","log_console"))
		#声明一个全局日志的变量
		global py_common_logger  
		py_common_logger = PY_Common_Log()  
		if py_common_logger.init(Path,Pre,Level,Interval,Key,Console)<0:
			return -1
		#py_common_logger.print_log()
		return 0
	except Exception,e:
		print ":init error:%s"%(str(e))
		return -1

def SET_LOG_KEY(log_key):
	try:
		if py_common_logger:
			py_common_logger.set_log_key(log_key)
	except Exception,e:
		print ":debug error:%s"%(str(e))

def DEBUG_LOG(*debug_log_args):
	try:
		if py_common_logger is None:
			print "|".join(["DEBUG",":".join((str(e) for e in debug_log_args))])
		else:
			py_common_logger.debug(*debug_log_args)
	except Exception,e:
		print ":debug error:%s"%(str(e))

def INFO_LOG(*info_log_args):
	try:
		if py_common_logger is None:
			print "|".join(["INFO",":".join((str(e) for e in info_log_args))])
		else:
			py_common_logger.info(*info_log_args)
	except Exception,e:
		print ":info error:%s"%(str(e))

def WARN_LOG(*warn_log_args):
	try:
		if py_common_logger is None:
			print "|".join(["WARNING",":".join((str(e) for e in warn_log_args))])
		else:
			py_common_logger.warn(*warn_log_args)
	except Exception,e:
		print ":warn error:%s"%(str(e))

def ERROR_LOG(*error_log_args):
	try:
		if py_common_logger is None:
			print "|".join(["ERROR",":".join((str(e) for e in error_log_args))])
		else:
			py_common_logger.error(*error_log_args)
	except Exception,e:
		print ":error error:%s"%(str(e))

def BUSINESS_LOG(*business_log_args):
	try:
		if py_common_logger is None:
			print "|".join(["BUSINESS",":".join((str(e) for e in business_log_args))])
		else:
			py_common_logger.business(*business_log_args)
	except Exception,e:
		print ":business error:%s"%(str(e))




"""
过滤器:过滤CRITICAL级别的日志打印
"""
class CriticalContextFilter(logging.Filter):
	def filter(self,record):
		if record.levelno == logging.CRITICAL:
			return False
		return True

"""
日志类
"""
class PY_Common_Log():
	def __init__(self,Path='./',Pre='',Level=10,Interval=2,Key="mylog",Console=0):
		self._log_path = Path 
		self._log_pre = Pre
		self._log_level = Level             #默认DEBUG级别,即所有都打印
		self._log_interval = Interval
		self._log_key = Key
		self._log_console = Console         #控制台是否输出日志
		self._logger = None                 #日志实例
		self._record_log_key = "common"     #用于记录某条日志的名称,便于日志分析 
		self._cn_ = self.__class__.__name__ #classname,for log debug
	
	def print_log(self):
		print "start!!!!!!!!!!!!!!!!!!!!!!!!"
		print "path=",self._log_path
		print "pre=",self._log_pre
		print "level=",self._log_level
		print "interval=",self._log_interval
		print "key=",self._log_key
		print "console=",self._log_console
		print "record_key=",self._record_log_key

	def init(self,Path,Pre='',Level=10,Interval=2,Key='mylog',Console=0):
		_fn_ = inspect.currentframe().f_code.co_name
		try:
			self.__init__(Path,Pre,Level,Interval,Key,Console)
			#check args#
			if not self._log_path:
				print "Path is empty,invalid!!!"
				return -1
			if self._log_level not in LEVEL_TYPE_DICT.keys():
				print 'Level invalid!!!(example:10/20/30/40/50)'
				return -1
			if self._log_interval not in INTERNAL_DICT.keys():
				print 'Interval invalid!!!(example:0/1/2/3/4)'
				return -1
			if not self._log_key:
				print "Key is empty,invalid!!!"
				return -1
			if self._log_console not in CONSOLE_TYPE_DICT.keys():
				print "Console invalid!!!(example:0/1)"
				return -1

			#创建run_logger实例#
			if self._logger:
				self._logger = None
			self._logger = logging.getLogger(self._log_key)
			self._logger.setLevel(logging.DEBUG)
			
			#增加debug轮询文件句柄#
			fh_program = logging.handlers.TimedRotatingFileHandler(
											self._get_log_name(logging.DEBUG),
											WHEN_DICT[self._log_interval],
											INTERNAL_DICT[self._log_interval],0)
			fh_program.suffix = SUFFIX_DICT[self._log_interval]
			fh_program.setLevel(self._log_level) #根据配置文件设置打印级别#
			
			#增加error轮询文件句柄#
			fh_error = logging.handlers.TimedRotatingFileHandler(
											self._get_log_name(logging.ERROR),
											WHEN_DICT[self._log_interval],
											INTERNAL_DICT[self._log_interval],0)
			fh_error.suffix = SUFFIX_DICT[self._log_interval]
			fh_error.setLevel(logging.ERROR) #只打印error级别#
			
			#增加business轮询文件句柄#
			fh_business = logging.handlers.TimedRotatingFileHandler(
											self._get_log_name(logging.CRITICAL),
											WHEN_DICT[self._log_interval],
											INTERNAL_DICT[self._log_interval],0)
			fh_business.suffix = SUFFIX_DICT[self._log_interval]
			fh_business.setLevel(logging.CRITICAL) #只打印critical级别#

			#增加过滤器:program和error禁止输出critical级别的错误#
			f = CriticalContextFilter()
			fh_program.addFilter(f)
			fh_error.addFilter(f)
			
			#定义program和error的输出格式#
			#%(pathname)s|%(filename)s|%(module)s|%(lineno)s|%(funcName)s|
			fmt_log = '%(process)d|%(asctime)s|%(levelname)s|%(message)s'
			run_fmt = logging.Formatter(fmt_log,DATEFORMAT)
			fh_program.setFormatter(run_fmt)
			fh_error.setFormatter(run_fmt)
			#business的输出格式#
			fmt_log = '%(process)d|%(asctime)s|%(message)s'
			bns_fmt = logging.Formatter(fmt_log,DATEFORMAT)
			fh_business.setFormatter(bns_fmt)

			self._logger.addHandler(fh_program)
			self._logger.addHandler(fh_error)
			self._logger.addHandler(fh_business)

			#添加控制台输出句柄#
			if self._log_console:
				ch_ctrl = logging.StreamHandler()
				ch_ctrl.setLevel(logging.DEBUG)
				#%(pathname)s|%(filename)s|%(module)s|%(lineno)s|%(funcName)s|
				fmt_log = '%(levelname)s|%(message)s'
				ctrl_fmt = logging.Formatter(fmt_log)
				ch_ctrl.setFormatter(ctrl_fmt)
				self._logger.addHandler(ch_ctrl)
			return 0
		except Exception,e:
			print ":init error:%s"%str(e)
			return -1

	#拼装日志格式#
	def _get_log_name(self,log_level):
		path_pre_name = ""
		if self._log_pre:
			path_pre = "/".join([self._log_path,self._log_pre])
			path_pre_name = "_".join([path_pre,LOG_TYPE_DICT[log_level]])
		else:
			path_pre_name = "/".join([self._log_path,LOG_TYPE_DICT[log_level]])
		return  ".".join([path_pre_name,"log"])

	#设置日志记录标识#
	def set_log_key(self,record_key):
		self._record_log_key = record_key

	#调试日志文件输出
	def debug(self,*format_args):
		self._logger.debug("|".join([self._record_log_key,":".join((str(e) for e in format_args))]))
	
	def info(self,*format_args):
		self._logger.info("|".join([self._record_log_key,":".join((str(e) for e in format_args))]))

	def warn(self,*format_args):
		self._logger.warning("|".join([self._record_log_key,":".join((str(e) for e in format_args))]))

	#错误日志文件输出,特别地错误同时也会打到调试日志中
	def error(self,*format_args):
		self._logger.error("|".join([self._record_log_key,":".join((str(e) for e in format_args))]))

	#业务日志文件输出
	def business(self,*format_args):
		self._logger.critical("|".join((str(e) for e in format_args)))
		pass



if __name__ == "__main__":
	_fn_ = "main"
	log_config = '../log.config'	
	mode = 0

	try:
		if len(sys.argv) == 2:
			mode = int(sys.argv[1])
		
		if mode == 1:
			#直接输出测试#
			DEBUG_LOG("output",_fn_,"data","real",1111)
			INFO_LOG("output",_fn_,"info","test",22222222)
			WARN_LOG("output",_fn_,"warning",4444444444)
			ERROR_LOG("output",_fn_,"error!!!!!!!",77777777777)
			BUSINESS_LOG("output","192.168.10.124","interface","request",10101010)
		else:
			#文件输出测试#
			if INIT_LOG(log_config) < 0:
				print 'py_common_logger init error'
				exit(-1)
			times = 0
			while True:
				times = times + 1
				SET_LOG_KEY("TEST")
				DEBUG_LOG("interface",_fn_,"data","real",times)
				INFO_LOG("interface",_fn_,"info","test",times)
				WARN_LOG(_fn_,"warning",times)

				ERROR_LOG(_fn_,"error!!!!!!!",times)
				
				BUSINESS_LOG("192.168.10.124","interface","request",times)

				time.sleep(5)
				if times > 2:
					print "finish loop!!!!!!!!!!!!!!!!!!!!"
					break
		exit(0)
	except Exception,e:
		print 'error:%s'%(str(e))
		exit(-1)



